package com.mapler.ngfx.service;

import com.mapler.model.AdModel;
import com.mapler.model.SModel;
import com.mapler.model.UAModel;
import com.mapler.service.INotifier;
import com.mapler.service.MailRunner;
import com.mapler.utility.HttpHelper;
import com.mapler.utility.IConstant;
import com.mapler.utility.Util;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Random;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

/**
 *
 * @author none
 */
public class NGFXSignupClick implements Runnable {

    private SModel sModel;
    private ArrayList<UAModel> uaModels;
    ArrayList<AdModel> addModels;
    private Random random;
    private HashMap<String, UAModel> usHashMap;
    private static Logger log = Logger.getLogger(NGFXSignupClick.class);
    private INotifier iNotifier;
    String[] months = {"January:01", "February:02", "March:03", "April:04", "May:05", "June:06", "July:07", "August:08", "September:09", "October:10", "November:11", "December:12"};
    String[] days = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31"};
    String[] charset = {"a", "b", "1", "c", "d", "e", "2", "f", "g", "h", "3", "i", "j", "k", "4", "l", "m", "n", "o", "5", "p", "q", "r", "6", "s", "t", "7", "u", "v", "8", "w", "x", "y", "9", "z"};

    public NGFXSignupClick(INotifier iNotifier, SModel sModel, ArrayList<UAModel> uaModels, ArrayList<AdModel> addModels,
            HashMap<String, UAModel> usHashMap) {
        this.sModel = sModel;
        this.uaModels = uaModels;
        this.addModels = addModels;
        this.usHashMap = usHashMap;
        this.iNotifier = iNotifier;
    }

    public NGFXSignupClick(SModel iModel) {
        this.sModel = iModel;
    }

    public Random getRandom() {
        if (random == null) {
            random = new Random();
        }
        return random;
    }

    public void setRandom(Random random) {
        this.random = random;
    }

    @Override
    public void run() {
        try {
            if (sModel.isIsVPN()) {
                log.debug("Signup:Run::Going to run for VPN");
                this.init();
                log.debug("Signup:Run::Done !!!");
            } else {
                log.debug("Signup:Run::Going to run for SOCKS");
                this.init();
                log.debug("Signup:Run::Done !!!");
            }
        } catch (Throwable ex) {
            iNotifier.notify("Signup:Run:: stopped for error: " + ex.getMessage());
            log.error("Signup:Run:: stopped causes " + ex);
        }
    }

    private void init() {
        if (sModel.getProxy().isEmpty() || sModel.getName().isEmpty() || sModel.getPass().isEmpty()) {
            iNotifier.notify("Signup:: Stop working proxy, username or password is empty");
            log.debug("Signup:: Stop working proxy, username or password is empty");
            return;
        }
        for (UAModel uam : uaModels) {
            try {
                if (sModel.isStopEngine()) {
                    break;
                }
                iNotifier.notify("Signup:: Going to connect VPN for " + sModel.getProxy());
                boolean connect = Util.connect(sModel.getProxy(), sModel.getName(), sModel.getPass());
                if (!connect) {
                    iNotifier.notify("Signup:: unable to connect VPN.");
                    log.debug("Signup:: unable to connect for " + uam.getProxy());
                    //Util.updateNGFXWorking(sModel, uam.getId(), 1);
                    continue;
                }
                //Util.updateNGFXWorking(sModel, uam.getId(), 1);

                iNotifier.notify("Signup:: Goting to start signup for " + uam.getEmail());
                log.debug("Signup:: Goting to start signup for " + uam.getEmail());
                this.doPost(uam);
                iNotifier.notify("Signup:: Signup done for " + uam.getEmail());
                log.debug("Signup:: Signup done for " + uam.getEmail());

                iNotifier.notify("Signup:: Going to disconnect for " + sModel.getProxy());
                log.debug("Signup:: Going to disconnect for " + sModel.getProxy());
                boolean disconnect = Util.disConnect(sModel.getProxy(), sModel.getName(), sModel.getPass());
                if (!disconnect) {
                    iNotifier.notify("Signup:: unable to disconnec VPN ");
                    log.debug("Signup:goVPN:: unable to disconnect VPN(no more further action) for " + sModel.getProxy());
                    break;
                } else {
                    iNotifier.notify("Signup:: disconnected from VPN ");
                    log.debug("Signup:: disconnected form VPN ");
                }

                //iNotifier.notify("Signup:: Going to clean working directory ");
                //Util.deleteFXTmpDirectory();

                iNotifier.notify("Signup:: Waiting 3 sec for before another signup.");
                Util.wait(3);

            } catch (Throwable ex) {
                iNotifier.notify("Signup::Critical error on signup. No more work..." + ex.getMessage());
                log.debug("Signup::Critical error on signup. No more work..." + ex);
            }
        }
        iNotifier.notify("Signup:: Finished work !!! ");
        log.debug("Signup:: Finished work !!! ");
    }

    private void doPost(UAModel uam) {
        WebDriver driver = null;
        try {
            driver = Util.createDriver(sModel, uam);
            if (driver == null) {
                iNotifier.notify("Signup:: unable to init driver. driver is null");
                log.debug("Signup:doPost:: driver is null. Unable to init driver");
                throw new Exception("Signup:doPost:: driver is null. Unable to init driver");
            }

            iNotifier.notify("Signup:: Working for account :" + " Email :" + uam.getEmail() + ", Please wait ...");

            driver.get(sModel.getLink());
            Util.byClickTag(driver, "a", "rel", "nofollow");

            Util.wait(3);
            WebElement element = driver.findElement(By.id("month"));
            if (element == null) {
                iNotifier.notify("Signup:: Month not found.");
                log.debug("Signup:doPost:: Month not found.");
                throw new Exception("Signup:doPost:: Month not found.");
            }
            String month = months[this.getRandom().nextInt(months.length - 1)];
            element.sendKeys(month.split(":")[0]);

            element = driver.findElement(By.id("day"));
            if (element == null) {
                iNotifier.notify("Signup:: Day not found.");
                log.debug("Signup:doPost:: Day not found.");
                throw new Exception("Signup:doPost:: Day not found.");
            }
            String day = days[this.getRandom().nextInt(days.length - 1)];
            element.sendKeys(day);

            element = driver.findElement(By.id("year"));
            if (element == null) {
                iNotifier.notify("Signup:: year not found.");
                log.debug("Signup:doPost:: year not found.");
                throw new Exception("Signup:doPost:: year not found.");
            }
            Calendar now = Calendar.getInstance();
            int year = now.get(Calendar.YEAR);
            int maxYear = year - 18;
            int minYear = year - 35;
            year = this.getRandom().nextInt(maxYear - minYear + 1) + minYear;
            element.sendKeys("" + year);

            String dateofbirth = year + "-" + month.split(":")[1] + "-" + day;

            Util.byButton(driver, "input", "value", "Proceed…");

            Util.wait(2);
            WebElement eleUName = driver.findElement(By.id("regusername"));
            if (eleUName == null) {
                iNotifier.notify("Signup:: username not found.");
                log.debug("Signup:doPost:: username not found.");
                throw new Exception("Signup:doPost:: username not found.");
            }
            if (!uam.getEmail().contains("@")) {
                iNotifier.notify("Signup:: email address not valid.");
                log.debug("Signup:doPost:: email address not valid.");
                throw new Exception("Signup:doPost:: email address not valid.");
            }

            WebElement eleCMsg = driver.findElement(By.id("reg_verif_div"));
            if (eleCMsg == null) {
                iNotifier.notify("Signup:: confirmation div not found.");
                log.debug("Signup:doPost:: confirmation div not found.");
                throw new Exception("Signup:doPost:: confirmation div not found.");
            }

            //String username = uam.getEmail().split("@")[0] + uam.getEmail().split("@")[1];
            //username = username.replace("+", "").replace(".", "").replace("com", "");
            String username = uam.getEmail().split("@")[0];
            for (int i = 0;; i++) {
                eleUName.sendKeys(username);
                Util.wait(2);

                if (eleCMsg.getText().contains("Username is valid and not in use.")) {
                    break;
                } else if (eleCMsg.getText().contains("That username is already in use")) {
                    iNotifier.notify("Signup:doPost:: User name exists. going to try for another one.");
                    username += i;
                    eleUName.clear();
                }
            }
            String password = this.getPassword();
            if (password.isEmpty()) {
                password = "12345";
            }
            Util.sendKeysById(driver, "password", password);
            Util.sendKeysById(driver, "passwordconfirm", password);

            Util.sendKeysById(driver, "email", uam.getEmail());
            Util.sendKeysById(driver, "emailconfirm", uam.getEmail());

            List<WebElement> elements = driver.findElements(By.tagName("input"));
            WebElement eleHumVerify1 = null;
            for (WebElement elementLink : elements) {
                if (elementLink.getAttribute("name") != null
                        && elementLink.getAttribute("name").equalsIgnoreCase(
                        "nospamimg")) {
                    eleHumVerify1 = elementLink;
                    break;
                }
            }

            WebElement eleHumVerify2 = driver.findElement(By.id("recaptcha_response_field"));
            if (eleHumVerify2 == null) {
                iNotifier.notify("Signup:: captcha not valid or not found.");
                log.debug("Signup:doPost:: captcha not valid or not found.");
                throw new Exception("Signup:doPost:: captcha not valid or not found.");
            }

            element = driver.findElement(By.id("cb_rules_agree"));
            for (int i = 0;; i++) {
                Util.wait(1);
                if (element.isSelected()) {
                    break;
                }
            }

            Util.wait(1);
            String fvcode = eleHumVerify1.getAttribute("value");
            String svcode = eleHumVerify2.getAttribute("value");
            String refCode = driver.findElement(By.id("referrerfield_ctrl")).getAttribute("value");
            //Util.byClickTag(driver, "cb_rules_agree");

            Util.byButton(driver, "input", "value", "Complete Registration");

            iNotifier.notify("Signup:doPost:: Going to check post validity.");
            Util.wait(2);
            if (!checkValidPost(driver, uam)) {
                iNotifier.notify("Signup:: captcha or varification code is not valid or not found.");
                log.debug("Signup:doPost:: captcha or varification code is not valid or not found.");
                throw new Exception("Signup:doPost:: captcha or varification code is not valid or not found.");
            }

            iNotifier.notify("Signup:doPost:: Going to check post success.");
            Util.wait(2);
            if (!checkPostSuccess(driver)) {
                iNotifier.notify("Signup:: Post is not success going to try for another one.");
                log.debug("Signup:doPost:: Post is not success going to try for another one.");
                throw new Exception("Signup:doPost:: Post is not success going to try for another one.");
            }

            iNotifier.notify("Waiting 5 sec to call email checker.");
            Util.wait(5);
            iNotifier.notify("Signup:doPost:: going to check email.");
            MailRunner mailRunner = new MailRunner(iNotifier, sModel, uam);
            mailRunner.checkNGFXEmail(driver);

            /* if working is 0 means fresh account if 1 means bad account,if 2 then perfect account if 3 then perfect but without mail varification */
            int working = 2;
            if (!uam.isMailFound()) {
                working = 3;
                iNotifier.notify("Signup:doPost:: Link not found going to work for another account.");
                log.debug("Signup:doPost:: Link not found going to work for another account.");
                //throw new Exception("Signup:doPost:: Link not found going to work for another account.");
            }

            /* update account information */
            try {
                StringBuilder request = new StringBuilder();
                request.append("<Request>");
                request.append("<id>").append(uam.getId()).append("</id>");
                request.append("<username>").append(sModel.getUsername()).append("</username>");
                request.append("<password>").append(sModel.getPassword()).append("</password>");
                request.append("<ngfx_username>").append(username).append("</ngfx_username>");
                request.append("<ngfx_password>").append(password).append("</ngfx_password>");
                request.append("<verify_code1>").append(fvcode).append("</verify_code1>");
                request.append("<verify_code2>").append(svcode).append("</verify_code2>");
                request.append("<date_of_birth>").append(dateofbirth).append("</date_of_birth>");
                request.append("<referral>").append(refCode).append("</referral>");
                request.append("<working>").append(working).append("</working>");
                request.append("</Request>");

                String req = URLEncoder.encode(request.toString(), "UTF-8");
                String uri = "http://" + IConstant.HOSTNAME + "/index.php?r=ngfxaccount/updateAccount";
                String param = "request=" + req;
                String response = HttpHelper.post(new URL(uri), param);

                Document document = DocumentHelper.parseText(response);
                String msg = document.valueOf("Response/message");
                iNotifier.notify("Signup:: " + msg);
            } catch (Exception ex) {
                iNotifier.notify("Signup:: problem on updating account " + ex.getMessage());
                log.debug("Signup:: problem on updating account " + ex.getMessage());
            }

        } catch (Throwable ex) {
            iNotifier.notify("Signup: Stopped for error: " + ex.getMessage());
            log.error("Signup:doPost:: Stopped causes..." + ex);
            ex.printStackTrace();
        } finally {
            if (driver != null) {
                driver.close();
            }
        }
    }

    private boolean checkValidPost(WebDriver driver, UAModel uam) {
        try {
            List<WebElement> elements = driver.findElements(By.tagName("ul"));
            for (WebElement elementLink : elements) {
                if (elementLink.getAttribute("class") != null
                        && elementLink.getAttribute("class").contains(
                        "blockrow")) {
                    if (elementLink.getText().contains("The email address you entered is already in use.")) {
                        Util.updateNGFXWorking(sModel, uam.getId(), 1);
                        return false;
                    } else if (elementLink.getText().contains("The string you entered for the image verification did not match what was displayed")) {
                        Util.updateNGFXWorking(sModel, uam.getId(), 0);
                        return false;
                    } else if (elementLink.getText().contains("You answered the Image Verification question incorrectly")) {
                        Util.updateNGFXWorking(sModel, uam.getId(), 0);
                        return false;
                    }
                }
            }
        } catch (Throwable ex) {
            log.debug("Problem on checking valid post.");
            iNotifier.notify("Problem on checking valid post");
            ex.printStackTrace();
        }
        return true;
    }

    private boolean checkPostSuccess(WebDriver driver) {
        try {
            List<WebElement> elements = driver.findElements(By.tagName("div"));
            for (WebElement elementLink : elements) {
                if (elementLink.getAttribute("class") != null
                        && elementLink.getAttribute("class").contains(
                        "blockrow restore")) {
                    if (elementLink.getText().contains("Thank you for registering")) {
                        return true;
                    }
                }
            }
        } catch (Throwable ex) {
            log.debug("Problem on checking posting success.");
            iNotifier.notify("Problem on checking posting success");
            ex.printStackTrace();
        }
        return false;
    }

    private String getPassword() {
        String password = "";
        for (int j = 1; j <= 7; j++) {
            password += charset[this.getRandom().nextInt(charset.length - 1)];
        }
        if (password.isEmpty()) {
            password = "123456";
        }
        return password;
    }

    public static void main(String s[]) {
        SModel sModel = new SModel();
        sModel.setDriver("FF");
        sModel.setLink("http://nigeria-forex.com/forum.php?referrerid=27246");
        sModel.setUseFWlink("0");
        sModel.setUsername("mithun");
        sModel.setPassword("mithun");
        sModel.setWebMail(false);
        NGFXSignupClick click = new NGFXSignupClick(sModel);
        UAModel model = new UAModel();
        model.setEmail("idmdtje@clirobot.com");
        model.setEmailPassword("gmail@@7");
        model.setUsername("prantoor");
        model.setPassword("pass123");
        model.setId("22");

        click.doPost(model);
        //click.doIT();

    }

    private void doIT() {
        SModel sModel = new SModel();
        sModel.setDriver("FF");
        sModel.setLink("http://nigeria-forex.com/forum.php?referrerid=27246");
        sModel.setUseFWlink("0");
        sModel.setUsername("mithun");
        sModel.setPassword("mithun");
        NGFXSignupClick click = new NGFXSignupClick(sModel);
        UAModel model = new UAModel();
        model.setEmail("skyroproject8@gmail.com");
        model.setEmailPassword("mn142536");
        model.setUsername("prantoor");
        model.setPassword("pass123");
        model.setId("22");
        MailRunner mailRunner = new MailRunner(iNotifier, sModel, model);
        mailRunner.checkNGFXEmail(null);
    }
}